home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / Installer SDK 1.2.4 / Upgrader 1.2.3 & Engines / Upgrader 1.2.3 / Plug-in Examples / Common Files / MWCPlusExtensions / ExceptionPPC.cp < prev    next >
Encoding:
Text File  |  2000-10-04  |  36.4 KB  |  1,000 lines  |  [TEXT/CWIE]

  1.  
  2. //
  3. //    ExceptionPPC.cp        -    Exception Handling Runtime Support for CodeWarriorâ„¢ (PowerPC)
  4. //
  5. //  Copyright Â© 1995 metrowerks inc.  All rights reserved.
  6. //
  7. //
  8. //    POWERPC STACK FRAME FORMAT
  9. //
  10. //    The PowerPC runtime architecture uses a grow-down stack with a single stack
  11. //    pointer at the low address end. The stack has the following organization:
  12. //    
  13. //
  14. //    LOW ADDRESSES    |                        |
  15. //                    |                        |
  16. //                    |-----------------------|
  17. //                    |    GPR save area        |
  18. //                    |-----------------------|    Can be used by frameless leaf routines
  19. //                    |    FPR save area        |
  20. //    Callee's SP   =>|-----------------------|
  21. //                    |        Callee's        |
  22. //                    |      linkage area        |
  23. //                    |-----------------------|
  24. //                    |        Callee's        |    Storage for parameters passed to
  25. //                    |    parameter area        |    routines called by callee
  26. //                    |-----------------------|
  27. //                    |        Callee's        |
  28. //                    |    local variables        |
  29. //                    |-----------------------|
  30. //                    |    alignment gap 1        |
  31. //                    |-----------------------|
  32. //                    |    GPR save area        |    Storage for nonvolatile GPRs used by callee
  33. //                    |-----------------------|
  34. //                    |    alignment gap 2        |
  35. //                    |-----------------------|
  36. //                    |    FPR save area        |    Storage for nonvolatile FPRs used by callee
  37. //    Caller's SP   =>|-----------------------|
  38. //                    |        Caller's        |
  39. //                    |      linkage area        |
  40. //                    |-----------------------|
  41. //                    |        Caller's        |    Storage for parameters passed to
  42. //                    |    parameter area        |    callee
  43. //                    |-----------------------|
  44. //                    |        Caller's        |
  45. //                    |    local variables        |
  46. //                    |-----------------------|
  47. //                    |                        |
  48. //    HIGH ADDRESSES    |                        |
  49. //
  50. //
  51. //    where the "linkage area" looks like this:
  52. //
  53. //
  54. //                    |-----------------------|
  55. //                0    | Stack Frame Back Link    |    Pointer to caller's frame
  56. //                    |-----------------------|
  57. //                4    |        Saved CR        |    Our CR (saved by routines we call)
  58. //                    |-----------------------|
  59. //                8    |        Saved LR        |    Our LR (saved by routines we call)
  60. //                    |-----------------------|
  61. //                12    |        (Reserved)        |
  62. //                    |-----------------------|
  63. //                16    |        (Reserved)        |
  64. //                    |-----------------------|
  65. //                20    |    Saved TOC Pointer    |    Our TOC (saved by cross-TOC glue)
  66. //                    |-----------------------|
  67. //
  68. //
  69. //    To unwind the stack, we start with a return address and SP for the routine which
  70. //    threw the exception. The next return address can be found by following the
  71. //    back-link at 0(SP) and accessing the saved LR in that frame.
  72. //
  73. //    Restoring registers is slightly more tricky. If 'saved_CR' is true, we restore
  74. //    the CR from the callers linkage area. For saved GPRs and FPRs we start with
  75. //    the callers SP; the <n> saved FPRs will be at <callers SP> - (8 * <n>) and the
  76. //    <m> saved GPRs will be the (<m> * 4) words ending at at <callers SP> - (8 * <n>)
  77. //    adjusted so that the last word ends on a 16-byte boundary. (See below)
  78. //
  79. //
  80.  
  81. #define __NOSTRING__    //    do not include <string>
  82.  
  83. #include <stdlib.h>
  84. #include <CPlusLib.h>
  85. #include <exception.h>
  86. #include "ExceptionPPC.h"
  87. #include "NMWException.h"
  88.  
  89. #if 1
  90. #define INLINE            static                //    static for debugging
  91. #else
  92. #define INLINE            inline                //    inline for shipping code
  93. #endif
  94.  
  95. //    typedefs
  96.  
  97. typedef struct ThrowContext {
  98.     double        FPR[32];                    //    FPR0-FPR31    (not all are saved/restored)
  99.     long        GPR[32];                    //    GPR0-GPR31    (not all are saved/restored)
  100.     long        CR;                            //    CR0-CR7
  101.     char*        SP;                            //    stack pointer during unwind (used for linkage)
  102.     char*        FP;                            //    frame pointer during unwind (used for locals)
  103.     char*        throwSP;                    //    stack pointer at throw
  104.     char*        returnaddr;                    //    return address
  105.     char*        throwtype;                    //    throw type argument (0L: rethrow: throw; )
  106.     void*        location;                    //    location argument (0L: rethrow: throw; )
  107.     void*        dtor;                        //    dtor argument
  108.     CatchInfo    *catchinfo;                    //    pointer to rethrow CatchInfo (or 0L)    
  109. }    ThrowContext;
  110.  
  111. typedef struct MWExceptionInfo {
  112.     ExceptionTable*    exception_record;        //    pointer to exception table
  113.     char*            current_function;        //    pointer to current function
  114.     char*            action_pointer;            //    pointer to action
  115.     char*            code_section;            //    base of code section for fragment containing table
  116.     char*            data_section;            //    base of data section for fragment containing table
  117.     char*            TOC;                    //    TOC pointer for fragment containing table
  118. }    MWExceptionInfo;
  119.  
  120. typedef struct FragmentInfo {
  121.     ExceptionTableIndex*    exception_start;    //    start of exception table index for fragment
  122.     ExceptionTableIndex*    exception_end;        //    end of exception table index for fragment
  123.     char*                    code_start;            //    start of code section for fragment
  124.     char*                    code_end;            //    end of code section for fragment
  125.     char*                    data_start;            //    start of data section for fragment
  126.     char*                    data_end;            //    end of data section for fragment
  127.     char*                    TOC;                //    TOC pointer for fragment
  128. } FragmentInfo;
  129.  
  130. typedef struct ActionIterator {
  131.     MWExceptionInfo    info;                    //    pointer to exception record
  132.     char*            current_SP;                //    current stack pointer
  133.     char*            current_FP;                //    current frame pointer (SP or R31)
  134.     long            current_R31;            //    current R31
  135. }    ActionIterator;
  136.  
  137. #define    MAXFRAGMENTS    32                    //    maximum # of code fragments we can register
  138. static FragmentInfo fragmentinfo[MAXFRAGMENTS];
  139.  
  140. typedef void (*DeleteFunc)(void *);
  141.  
  142.  
  143. /************************************************************************/
  144. /* Purpose..: Register a code fragment and its exception tables            */
  145. /* Input....: pointer to start of fragments code section                */
  146. /* Input....: pointer to end   of fragments code section                */
  147. /* Input....: pointer to start of fragments data section                */
  148. /* Input....: pointer to end   of fragments data section                */
  149. /* Input....: pointer to start of fragments exception table index        */
  150. /* Input....: pointer to end   of fragments exception table index        */
  151. /* Input....: RTOC for fragment                                            */
  152. /* Return...: unique ID for __ex_unregister_fragment                    */
  153. /************************************************************************/
  154. int __register_fragment(char *code_start, char *code_end,
  155.                         char *data_start, char *data_end,
  156.                         char *exception_start, char *exception_end,
  157.                         char *TOC)
  158. {
  159.     FragmentInfo *f;
  160.     int i;
  161.     
  162.     //    find a free entry in the fragment table
  163.     for(i=0,f=fragmentinfo;i<MAXFRAGMENTS;++i,++f) if(f->code_start==0)
  164.     {
  165.         f->code_start=code_start;
  166.         f->code_end=code_end;
  167.         f->data_start=data_start;
  168.         f->data_end=data_end;
  169.         f->exception_start=(ExceptionTableIndex *)exception_start;
  170.         f->exception_end=(ExceptionTableIndex *)exception_end;
  171.         f->TOC=TOC;
  172.         return(i);
  173.     }
  174.     //    couldn't register the fragment
  175.     return(-1);
  176. }
  177.  
  178. /************************************************************************/
  179. /* Purpose..: Un-register a code fragment and its exception tables        */
  180. /* Input....: unique ID assigned in __ex_register_fragment                */
  181. /* Return...: ---                                                        */
  182. /************************************************************************/
  183. void __unregister_fragment(int fragmentID)
  184. {
  185.     FragmentInfo *f;
  186.     
  187.     if(fragmentID>=0 && fragmentID<MAXFRAGMENTS)
  188.     {
  189.         f = &fragmentinfo[fragmentID];
  190.         f->code_start=0; f->code_end=0;
  191.         f->data_start=0; f->data_end=0;
  192.         f->exception_start=0; f->exception_end=0;
  193.         f->TOC=0;
  194.     }
  195. }
  196.  
  197. /************************************************************************/
  198. /* Purpose..: Get an exception fragment record pointer                    */
  199. /* Input....: pointer to return address                                    */
  200. /* Return...: pointer to FragmentInfo struct                             */
  201. /************************************************************************/
  202. static FragmentInfo *ExPPC_FindExceptionFragment(char *returnaddr)
  203. {
  204.     FragmentInfo *f;
  205.     int i;
  206.     
  207.     for(i=0,f=fragmentinfo;i<MAXFRAGMENTS;++i,++f) if(f->code_start!=0)
  208.     {
  209.         if(returnaddr>=f->code_start && returnaddr<f->code_end) return(f);
  210.     }
  211.     
  212.     return(0);
  213. }
  214.  
  215. /************************************************************************/
  216. /* Purpose..: Get a exception record pointer                            */
  217. /* Input....: pointer to return address                                    */
  218. /* Input....: pointer to MWExceptionInfo struct for result                */
  219. /* Return...: ---                                                        */
  220. /************************************************************************/
  221. static void ExPPC_FindExceptionRecord(char *returnaddr,MWExceptionInfo *info)
  222. {
  223.     FragmentInfo *fragment;
  224.     ExceptionTableIndex *exceptionindex,*p;
  225.     ExceptionRange *r;
  226.     unsigned long returnoffset,i,m,n;
  227.  
  228.     //    so far we haven't found anything
  229.     info->exception_record=0;
  230.     info->action_pointer=0;
  231.     
  232.     //    find the exception table for the fragment containing 'returnaddr'
  233.     if ((fragment=ExPPC_FindExceptionFragment(returnaddr))==0) return;
  234.     info->code_section=fragment->code_start;
  235.     info->data_section=fragment->data_start;
  236.     info->TOC=fragment->TOC;
  237.     
  238.     //    binary-search the exception table index for a function containing 'returnaddr'
  239.     returnoffset=returnaddr-fragment->code_start;
  240.     exceptionindex=fragment->exception_start;
  241.     for(i=0,n=fragment->exception_end-fragment->exception_start;;)
  242.     {
  243.         if(i>n) return;
  244.         p=&exceptionindex[m=(i+n)/2];
  245.         if(returnoffset<p->functionoffset) n=m-1;
  246.         else if(returnoffset>p->functionoffset+p->functionsize) i=m+1;
  247.         else break;
  248.     }
  249.     info->current_function=fragment->code_start+p->functionoffset;
  250.     info->exception_record=p->directstore?(ExceptionTable *)(&p->exceptionoffset)
  251.                                         :(ExceptionTable *)(fragment->data_start+p->exceptionoffset);
  252.     
  253.     //    find the set of actions to perform for an exception thrown from 'returnaddr'
  254.     returnoffset-=p->functionoffset;
  255.     for(r=info->exception_record->ranges; r->start!=0; r++)
  256.     {
  257.         if(r->start<=returnoffset && r->end>=returnoffset)
  258.         {
  259.             info->action_pointer=(char *)info->exception_record+r->action; break;
  260.         }
  261.     }
  262. }
  263.  
  264. /************************************************************************/
  265. /* Purpose..: Find R31 saved in given stack frame                        */
  266. /* Input....: pointer to throw context                                    */
  267. /* Input....: pointer to topmost exception record                        */
  268. /* Return...: pointer to return PC                                        */
  269. /************************************************************************/
  270. static long ExPPC_PopR31(char *SP,MWExceptionInfo *info)
  271. {
  272.     double *FPR_save_area;
  273.     long *GPR_save_area;
  274.     int saved_GPRs, saved_FPRs;
  275.     
  276.     //    find saved FPRs
  277.     saved_FPRs=info->exception_record->savedFPRs;
  278.     FPR_save_area=(double *)(SP-saved_FPRs*8);
  279.  
  280.     //  find saved GPRs
  281.     saved_GPRs=info->exception_record->savedGPRs;
  282.     GPR_save_area=(long *)FPR_save_area;
  283.     if(saved_FPRs&1) GPR_save_area-=2;  // 8-byte gap if # saved FPRs is odd
  284.  
  285.     //    return saved R31
  286.     return(GPR_save_area[-1]);    //    R31 is last register saved, has highest address
  287. }
  288.  
  289. /************************************************************************/
  290. /* Purpose..: Return current exception action type                        */
  291. /* Input....: pointer to ActionIterator                                    */
  292. /* Return...: action type                                                */
  293. /************************************************************************/
  294. static exaction_type ExPPC_CurrentAction(const ActionIterator *iter)
  295. {
  296.     if(iter->info.action_pointer==0) return EXACTION_ENDOFLIST;
  297.     return ((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
  298. }
  299.  
  300. /************************************************************************/
  301. /* Purpose..: Move to next action in Exception Table                    */
  302. /* Input....: pointer to ActionIterator                                    */
  303. /* Return...: next action type                                            */
  304. /************************************************************************/
  305. static exaction_type ExPPC_NextAction(ActionIterator *iter)
  306. {
  307.     exaction_type    action;
  308.  
  309.     for(;;)
  310.     {
  311.         if(    iter->info.action_pointer==0
  312.         ||    ((action=((ex_destroylocal *)iter->info.action_pointer)->action)&EXACTION_ENDBIT)!=0 )
  313.         {    //    end of action list: find next exception record
  314.             char *return_addr, *callers_SP;
  315.             
  316.             //    get LR saved in linkage area of caller
  317.             callers_SP=*(char **)iter->current_SP;
  318.             if(iter->info.exception_record->savedGPRs) iter->current_R31=ExPPC_PopR31(callers_SP,&iter->info);
  319.             return_addr=*(char **)(callers_SP+8);
  320.             ExPPC_FindExceptionRecord(return_addr,&iter->info);
  321.             if(iter->info.exception_record==0) terminate();    //    cannot find matching exception record
  322.             //    pop down to caller's stack frame
  323.             iter->current_SP=callers_SP;
  324.             iter->current_FP=(iter->info.exception_record->hasframeptr)?(char *)iter->current_R31:iter->current_SP;
  325.             if(iter->info.action_pointer==0) continue;        //    no actions
  326.         }
  327.         else
  328.         {
  329.             switch(action)
  330.             {
  331.             case EXACTION_DESTROYLOCAL:
  332.                 iter->info.action_pointer+=sizeof(ex_destroylocal); break;
  333.             case EXACTION_DESTROYLOCALCOND:
  334.                 iter->info.action_pointer+=sizeof(ex_destroylocalcond); break;
  335.             case EXACTION_DESTROYLOCALPOINTER:
  336.                 iter->info.action_pointer+=sizeof(ex_destroylocalpointer); break;
  337.             case EXACTION_DESTROYLOCALARRAY:
  338.                 iter->info.action_pointer+=sizeof(ex_destroylocalarray); break;
  339.             case EXACTION_DESTROYBASE:
  340.             case EXACTION_DESTROYMEMBER:
  341.                 iter->info.action_pointer+=sizeof(ex_destroymember); break;
  342.             case EXACTION_DESTROYMEMBERCOND:
  343.                 iter->info.action_pointer+=sizeof(ex_destroymembercond); break;
  344.             case EXACTION_DESTROYMEMBERARRAY:
  345.                 iter->info.action_pointer+=sizeof(ex_destroymemberarray); break;
  346.             case EXACTION_DELETEPOINTER:
  347.                 iter->info.action_pointer+=sizeof(ex_deletepointer); break;
  348.             case EXACTION_DELETEPOINTERCOND:
  349.                 iter->info.action_pointer+=sizeof(ex_deletepointercond); break;
  350.             case EXACTION_CATCHBLOCK:
  351.                 iter->info.action_pointer+=sizeof(ex_catchblock); break;
  352.             case EXACTION_ACTIVECATCHBLOCK:
  353.                 iter->info.action_pointer+=sizeof(ex_activecatchblock); break;
  354.             case EXACTION_SPECIFICATION:
  355.                 iter->info.action_pointer+=sizeof(ex_specification)+((ex_specification *)iter->info.action_pointer)->specs*sizeof(void *); break;
  356.             default:
  357.                 terminate();    //    error
  358.             }
  359.         }
  360.         action=((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
  361.         if(action==EXACTION_BRANCH)
  362.         {    //    skip to target action--we never return EXACTION_BRANCH to caller!
  363.             iter->info.action_pointer=((char *)iter->info.exception_record)+((ex_branch *)iter->info.action_pointer)->target;
  364.             action=((ex_destroylocal *)iter->info.action_pointer)->action&EXACTION_MASK;
  365.         }
  366.         return action;
  367.     }
  368. }
  369.  
  370. /************************************************************************/
  371. /* Purpose..: Restore registers                                            */
  372. /* Input....: pointer to throw context                                    */
  373. /* Input....: pointer to topmost exception record                        */
  374. /* Return...: pointer to return PC                                        */
  375. /************************************************************************/
  376. static char *ExPPC_PopStackFrame(ThrowContext *context,MWExceptionInfo *info)
  377. {
  378.     char *SP, *callers_SP;
  379.     double *FPR_save_area;
  380.     long *GPR_save_area;
  381.     int saved_GPRs, saved_FPRs;
  382.     int i, j;
  383.     
  384.     //    obtain current and callers frame pointers
  385.     SP=context->SP; callers_SP=*(char **)SP;
  386.     
  387.     //    restore saved FPRs
  388.     saved_FPRs=info->exception_record->savedFPRs;
  389.     FPR_save_area=(double *)(callers_SP-saved_FPRs*8);
  390.     for(i=32-saved_FPRs, j=0;i<32;++i,++j) context->FPR[i]=FPR_save_area[j];
  391.  
  392.     //  restore saved GPRs
  393.     saved_GPRs=info->exception_record->savedGPRs;
  394. //    GPR_save_area=(long *)(((long)FPR_save_area&0xFFFFFFF0)-saved_GPRs*4);
  395. //    for(i=32-saved_GPRs, j=0;i<32;++i,++j) context->GPR[i]=GPR_save_area[j];
  396.     GPR_save_area=(long *)FPR_save_area;
  397.     if(saved_FPRs&1) GPR_save_area-=2;  // 8-byte gap if # saved FPRs is odd
  398.     GPR_save_area-=saved_GPRs;
  399.     for(i=32-saved_GPRs, j=0;i<32;++i,++j) context->GPR[i]=GPR_save_area[j];
  400.     
  401.     //    restore saved CR
  402.     if(info->exception_record->savedCR) context->CR=*(long *)(callers_SP+4);
  403.     
  404.     //    restore saved SP (back link)
  405.     context->SP=callers_SP;
  406.     
  407.     //    return new return_addr
  408.     return(*(char **)(callers_SP+8));
  409. }
  410.  
  411. /************************************************************************/
  412. /* Purpose..: Unwind ex_destroylocal struct                                */
  413. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  414. /* Input....: pointer to throw context                                    */
  415. /* Input....: pointer to ex_destroylocal struct                            */
  416. /* Return...: ---                                                        */
  417. /************************************************************************/
  418. INLINE void ExPPC_DestroyLocal(ThrowContext *context,const ex_destroylocal *ex)
  419. {
  420.     DTORCALL_COMPLETE(ex->dtor,context->FP+ex->local);
  421. }
  422.  
  423. /************************************************************************/
  424. /* Purpose..: Unwind ex_destroylocalcond struct                            */
  425. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  426. /* Input....: pointer to throw context                                    */
  427. /* Input....: pointer to ex_destroylocalcond struct                        */
  428. /* Return...: ---                                                        */
  429. /************************************************************************/
  430. INLINE void ExPPC_DestroyLocalCond(ThrowContext *context,const ex_destroylocalcond *ex)
  431. {
  432.     int cond = ex->regcond    ? (local_cond_type) context->GPR[ex->cond]
  433.                             : *(local_cond_type *)(context->FP+ex->cond);
  434.  
  435.     if(cond) DTORCALL_COMPLETE(ex->dtor,context->FP+ex->local);
  436. }
  437.  
  438. /************************************************************************/
  439. /* Purpose..: Unwind ex_destroylocalpointer struct                        */
  440. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  441. /* Input....: pointer to throw context                                    */
  442. /* Input....: pointer to ex_destroylocalpointer struct                    */
  443. /* Return...: ---                                                        */
  444. /************************************************************************/
  445. INLINE void ExPPC_DestroyLocalPointer(ThrowContext *context,const ex_destroylocalpointer *ex)
  446. {
  447.     void *pointer = ex->regpointer    ? (void *) context->GPR[ex->pointer]
  448.                                     : *(void **)(context->FP+ex->pointer);
  449.  
  450.     DTORCALL_COMPLETE(ex->dtor,pointer);
  451. }
  452.  
  453. /************************************************************************/
  454. /* Purpose..: Unwind ex_destroylocalarray struct                        */
  455. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  456. /* Input....: pointer to throw context                                    */
  457. /* Input....: pointer to ex_destroylocalarray struct                    */
  458. /* Return...: ---                                                        */
  459. /************************************************************************/
  460. INLINE void ExPPC_DestroyLocalArray(ThrowContext *context,const ex_destroylocalarray *ex)
  461. {
  462.     char *ptr    = context->FP+ex->localarray;
  463.     long n        = ex->elements;
  464.     long size    = ex->element_size;
  465.  
  466.     for(ptr=ptr+size*n; n>0; n--)
  467.     {
  468.         ptr-=size; DTORCALL_COMPLETE(ex->dtor,ptr);
  469.     }
  470. }
  471.  
  472. /************************************************************************/
  473. /* Purpose..: Unwind ex_destroymember struct                            */
  474. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  475. /* Input....: pointer to throw context                                    */
  476. /* Input....: pointer to ex_destroymember struct                        */
  477. /* Return...: ---                                                        */
  478. /************************************************************************/
  479. INLINE void ExPPC_DestroyMember(ThrowContext *context,const ex_destroymember *ex)
  480. {
  481.     char *objectptr = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  482.                                         : *(char **)(context->FP+ex->objectptr);
  483.  
  484.     DTORCALL_COMPLETE(ex->dtor,objectptr+ex->offset);
  485. }
  486.  
  487. /************************************************************************/
  488. /* Purpose..: Unwind ex_destroymember struct                            */
  489. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  490. /* Input....: pointer to throw context                                    */
  491. /* Input....: pointer to ex_destroymember struct                        */
  492. /* Return...: ---                                                        */
  493. /************************************************************************/
  494. INLINE void ExPPC_DestroyBase(ThrowContext *context,const ex_destroymember *ex)
  495. {
  496.     char *objectptr = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  497.                                         : *(char **)(context->FP+ex->objectptr);
  498.  
  499.     DTORCALL_PARTIAL(ex->dtor,objectptr+ex->offset);
  500. }
  501.  
  502. /************************************************************************/
  503. /* Purpose..: Unwind ex_destroymembercond struct                        */
  504. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  505. /* Input....: pointer to throw context                                    */
  506. /* Input....: pointer to ex_destroymembercond struct                    */
  507. /* Return...: ---                                                        */
  508. /************************************************************************/
  509. INLINE void ExPPC_DestroyMemberCond(ThrowContext *context,const ex_destroymembercond *ex)
  510. {
  511.     char *objectptr = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  512.                                         : *(char **)(context->FP+ex->objectptr);
  513.     int cond = ex->regcond    ? (vbase_ctor_arg_type) context->GPR[ex->cond]
  514.                             : *(vbase_ctor_arg_type *)(context->FP+ex->cond);
  515.  
  516.     if(cond) DTORCALL_PARTIAL(ex->dtor,objectptr+ex->offset);
  517. }
  518.  
  519. /************************************************************************/
  520. /* Purpose..: Unwind ex_destroymemberarray struct                        */
  521. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  522. /* Input....: pointer to throw context                                    */
  523. /* Input....: pointer to ex_destroymemberarray struct                    */
  524. /* Return...: ---                                                        */
  525. /************************************************************************/
  526. INLINE void ExPPC_DestroyMemberArray(ThrowContext *context,const ex_destroymemberarray *ex)
  527. {
  528.     char *ptr    = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  529.                                     : *(char **)(context->FP+ex->objectptr);
  530.     long n        = ex->elements;
  531.     long size    = ex->element_size;
  532.  
  533.     for(ptr=ptr+size*n; n>0; n--)
  534.     {
  535.         ptr-=size; DTORCALL_COMPLETE(ex->dtor,ptr);
  536.     }
  537. }
  538.  
  539. /************************************************************************/
  540. /* Purpose..: Unwind ex_deletepointer struct                            */
  541. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  542. /* Input....: pointer to throw context                                    */
  543. /* Input....: pointer to ex_deletepointer struct                        */
  544. /* Return...: ---                                                        */
  545. /************************************************************************/
  546. INLINE void ExPPC_DeletePointer(ThrowContext *context,const ex_deletepointer *ex)
  547. {
  548.     char *objectptr = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  549.                                         : *(char **)(context->FP+ex->objectptr);
  550.  
  551.     ((DeleteFunc) ex->deletefunc)(objectptr);
  552. }
  553.  
  554. /************************************************************************/
  555. /* Purpose..: Unwind ex_deletepointercond struct                        */
  556. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  557. /* Input....: pointer to throw context                                    */
  558. /* Input....: pointer to ex_deletepointercond struct                    */
  559. /* Return...: ---                                                        */
  560. /************************************************************************/
  561. INLINE void ExPPC_DeletePointerCond(ThrowContext *context,const ex_deletepointercond *ex)
  562. {
  563.     char *objectptr = ex->regpointer    ? (char *) context->GPR[ex->objectptr]
  564.                                         : *(char **)(context->FP+ex->objectptr);
  565.     int cond = ex->regcond    ? (local_cond_type) context->GPR[ex->cond]
  566.                             : *(local_cond_type *)(context->FP+ex->cond);
  567.  
  568.     if(cond) ((DeleteFunc) ex->deletefunc)(objectptr);
  569. }
  570.  
  571. /************************************************************************/
  572. /* Purpose..: Unwind stack                                                */
  573. /* Input....: pointer to throw context                                    */
  574. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  575. /* Input....: pointer to topmost action                                    */
  576. /* Input....: pointer to catcher                                        */
  577. /* Return...: ---                                                        */
  578. /************************************************************************/
  579. static void ExPPC_UnwindStack(ThrowContext *context,MWExceptionInfo *info,void *catcher)
  580. {
  581.     exaction_type    action;
  582.  
  583. #pragma exception_terminate        //    this will prevent exception exits during unwindind
  584.  
  585.     for(;;)
  586.     {
  587.         if(info->action_pointer==0)
  588.         {
  589.             char *return_addr;
  590.     
  591.             return_addr=ExPPC_PopStackFrame(context,info);
  592.             ExPPC_FindExceptionRecord(return_addr,info);
  593.             if(info->exception_record==0) terminate();        //    cannot find matching exception record
  594.             context->FP=(info->exception_record->hasframeptr)?(char *)context->GPR[31]:context->SP;
  595.             continue;
  596.         }
  597.  
  598.         action=((ex_destroylocal *)info->action_pointer)->action;
  599.         switch(action&EXACTION_MASK)
  600.         {
  601.         case EXACTION_BRANCH:
  602.             info->action_pointer=((char *)info->exception_record)+((ex_branch *)info->action_pointer)->target; break;
  603.         
  604.         case EXACTION_DESTROYLOCAL:
  605.             ExPPC_DestroyLocal(context,(ex_destroylocal *)info->action_pointer);
  606.             info->action_pointer+=sizeof(ex_destroylocal); break;
  607.  
  608.         case EXACTION_DESTROYLOCALCOND:
  609.             ExPPC_DestroyLocalCond(context,(ex_destroylocalcond *)info->action_pointer);
  610.             info->action_pointer+=sizeof(ex_destroylocalcond); break;
  611.  
  612.         case EXACTION_DESTROYLOCALPOINTER:
  613.             ExPPC_DestroyLocalPointer(context,(ex_destroylocalpointer *)info->action_pointer);
  614.             info->action_pointer+=sizeof(ex_destroylocalpointer); break;
  615.  
  616.         case EXACTION_DESTROYLOCALARRAY:
  617.             ExPPC_DestroyLocalArray(context,(ex_destroylocalarray *)info->action_pointer);
  618.             info->action_pointer+=sizeof(ex_destroylocalarray); break;
  619.  
  620.         case EXACTION_DESTROYBASE:
  621.             ExPPC_DestroyBase(context,(ex_destroymember *)info->action_pointer);
  622.             info->action_pointer+=sizeof(ex_destroymember); break;
  623.  
  624.         case EXACTION_DESTROYMEMBER:
  625.             ExPPC_DestroyMember(context,(ex_destroymember *)info->action_pointer);
  626.             info->action_pointer+=sizeof(ex_destroymember); break;
  627.  
  628.         case EXACTION_DESTROYMEMBERCOND:
  629.             ExPPC_DestroyMemberCond(context,(ex_destroymembercond *)info->action_pointer);
  630.             info->action_pointer+=sizeof(ex_destroymembercond); break;
  631.  
  632.         case EXACTION_DESTROYMEMBERARRAY:
  633.             ExPPC_DestroyMemberArray(context,(ex_destroymemberarray *)info->action_pointer);
  634.             info->action_pointer+=sizeof(ex_destroymemberarray); break;
  635.  
  636.         case EXACTION_DELETEPOINTER:
  637.             ExPPC_DeletePointer(context,(ex_deletepointer *)info->action_pointer);
  638.             info->action_pointer+=sizeof(ex_deletepointer); break;
  639.  
  640.         case EXACTION_DELETEPOINTERCOND:
  641.             ExPPC_DeletePointerCond(context,(ex_deletepointercond *)info->action_pointer);
  642.             info->action_pointer+=sizeof(ex_deletepointercond); break;
  643.  
  644.         case EXACTION_CATCHBLOCK:
  645.             if(catcher==(void *)info->action_pointer) return;    //    finished unwinding
  646.             info->action_pointer+=sizeof(ex_catchblock); break;
  647.  
  648.         case EXACTION_ACTIVECATCHBLOCK:
  649.             {
  650.                 CatchInfo        *catchinfo;
  651.  
  652.                 catchinfo=(CatchInfo *)(context->FP+((ex_activecatchblock *)info->action_pointer)->cinfo_ref);
  653.                 if(context->catchinfo!=catchinfo && catchinfo->dtor)
  654.                 {
  655.                     DTORCALL_COMPLETE(catchinfo->dtor,catchinfo->location);
  656.                 }
  657.                 info->action_pointer+=sizeof(ex_activecatchblock);
  658.             }
  659.             break;
  660.  
  661.         case EXACTION_SPECIFICATION:
  662.             if(catcher==(void *)info->action_pointer) return;    //    finished unwinding
  663.             info->action_pointer+=sizeof(ex_specification)+((ex_specification *)info->action_pointer)->specs*sizeof(void *);
  664.             break;
  665.  
  666.         default:
  667.             terminate();            //    error
  668.         }
  669.         if(action&EXACTION_ENDBIT) info->action_pointer=0;
  670.     }
  671. }
  672.  
  673. /************************************************************************/
  674. /* Purpose..: Check if an exception is in a specification list            */
  675. /* Input....: pointer to exception type string                            */
  676. /* Input....: pointer to specification list                                */
  677. /* Return...: ---                                                        */
  678. /************************************************************************/
  679. static int ExPPC_IsInSpecification(char *extype,ex_specification *spec)
  680. {
  681.     long    i,offset;
  682.  
  683.     for(i=0; i<spec->specs; i++)
  684.     {
  685.         if(__throw_catch_compare(extype,spec->spec[i],&offset)) return 1;
  686.     }
  687.     return 0;
  688. }
  689.  
  690. /************************************************************************/
  691. /* Purpose..: Unexpected handler                                        */
  692. /* Input....: pointer to throw context                                    */
  693. /* Return...: --- (this function will never return)                        */
  694. /************************************************************************/
  695. extern void __unexpected(CatchInfo* catchinfo)
  696. {    
  697.     ex_specification *unexp=(ex_specification *)catchinfo->stacktop;
  698.  
  699. #pragma exception_magic
  700.  
  701.     try {
  702.         unexpected();
  703.     }
  704.     catch(...)
  705.     {    //    unexpected throws an exception => check if the exception matches the specification
  706.         if(ExPPC_IsInSpecification((char *)((CatchInfo *)&__exception_magic)->typeinfo,unexp))
  707.         {    //    new exception is in specification list => rethrow
  708.             throw;
  709.         }
  710.         if(ExPPC_IsInSpecification("!bad_exception!",unexp))
  711.         {    //    "bad_exception" is in specification list => throw bad_exception()
  712.             throw bad_exception();
  713.         }
  714.         //    cannot handle exception => terminate();
  715.     }
  716.     terminate();
  717. }
  718.  
  719. /************************************************************************/
  720. /* Purpose..: Restore registers and branch to catcher                    */
  721. /* Input....: pointer to throw context                                    */
  722. /* Input....: destination RTOC                                            */
  723. /* Input....: destination PC                                            */
  724. /* Return...: ---                                                        */
  725. /************************************************************************/
  726. static asm void ExPPC_LongJump(register ThrowContext *context, register void *newRTOC, register void *newPC)
  727. {
  728.         //    restore PC (LR)
  729.         mtlr    newPC
  730.         //    restore RTOC
  731.         mr        RTOC,newRTOC
  732.         //    restore CR
  733.         lwz        r0,context->CR
  734.         mtcrf    255,r0
  735.         //    restore R13-R31
  736.         lmw        r13,context->GPR[13]
  737.         //    restore FP14-FP31
  738.         lfd        fp14,context->FPR[14]
  739.         lfd        fp15,context->FPR[15]
  740.         lfd        fp16,context->FPR[16]
  741.         lfd        fp17,context->FPR[17]
  742.         lfd        fp18,context->FPR[18]
  743.         lfd        fp19,context->FPR[19]
  744.         lfd        fp20,context->FPR[20]
  745.         lfd        fp21,context->FPR[21]
  746.         lfd        fp22,context->FPR[22]
  747.         lfd        fp23,context->FPR[23]
  748.         lfd        fp24,context->FPR[24]
  749.         lfd        fp25,context->FPR[25]
  750.         lfd        fp26,context->FPR[26]
  751.         lfd        fp27,context->FPR[27]
  752.         lfd        fp28,context->FPR[28]
  753.         lfd        fp29,context->FPR[29]
  754.         lfd        fp30,context->FPR[30]
  755.         lfd        fp31,context->FPR[31]
  756.         //    restore SP to stack top at throw: discards exception-handling frames
  757.         //    but not exception temporaries
  758.         lwz        SP,context->throwSP
  759.         //    move stack frame back-link from catcher's linkage area to new top of
  760.         //    stack; this effectively pops all intermediate frames.
  761.         lwz        r3,context->SP
  762.         lwz        r3,0(r3)
  763.         stw        r3,0(SP)
  764.         //    jump to exception handler
  765.         blr
  766. }
  767.  
  768. /************************************************************************/
  769. /* Purpose..: Handle unexpected exception                                */
  770. /* Input....: pointer to throw context                                    */
  771. /* Input....: pointer to topmost MWExceptionInfo struct                    */
  772. /* Input....: pointer to specification record                            */
  773. /* Return...: ---                                                        */
  774. /************************************************************************/
  775. static void ExPPC_HandleUnexpected(ThrowContext *context,MWExceptionInfo *info,ex_specification *unexp)
  776. {
  777.     CatchInfo    *catchinfo;
  778.  
  779. #pragma exception_terminate        //    this will prevent exception exits during unwinding
  780.  
  781.     ExPPC_UnwindStack(context,info,unexp);    //    unwind stack to failing specification
  782.  
  783.     //    initialize catch info struct
  784.     catchinfo=(CatchInfo *)(context->FP+unexp->cinfo_ref);
  785.     catchinfo->location        = context->location;
  786.     catchinfo->typeinfo        = context->throwtype;
  787.     catchinfo->dtor            = context->dtor;
  788.     catchinfo->stacktop        = unexp;        //    the __unexpected will never call __end_catch
  789.                                             //    so we can resue this field
  790.     //    jump to exception handler
  791.     ExPPC_LongJump(context,info->TOC,info->current_function+unexp->pcoffset);
  792. }
  793.  
  794. /************************************************************************/
  795. /* Purpose..: Throw (rethrow) current exception                            */
  796. /* Input....: pointer to throw context                                    */
  797. /* Return...: ---                                                        */
  798. /************************************************************************/
  799. static void ExPPC_ThrowHandler(ThrowContext *context)
  800. {
  801.     ActionIterator    iter;
  802.     MWExceptionInfo    info;
  803.     exaction_type    action;
  804.     ex_catchblock    *catchblock;
  805.     CatchInfo        *catchinfo;
  806.     long            offset;
  807.  
  808.     //    find first ExceptionRecord
  809.     
  810.     ExPPC_FindExceptionRecord(context->returnaddr, &info);
  811.     if(info.exception_record==0) terminate();    //    cannot find matching exception record
  812.     context->FP=(info.exception_record->hasframeptr)?(char *)context->GPR[31]:context->SP;
  813.  
  814.     if(context->throwtype==0)
  815.     {    //    rethrow, find most recent exception
  816.         iter.info        = info;
  817.         iter.current_SP    = context->SP;
  818.         iter.current_FP    = context->FP;
  819.         iter.current_R31 = context->GPR[31];
  820.         for(action=ExPPC_CurrentAction(&iter);; action=ExPPC_NextAction(&iter))
  821.         {
  822.             switch(action)
  823.             {
  824.             case EXACTION_ACTIVECATCHBLOCK:
  825.                 break;
  826.     
  827.             case EXACTION_ENDOFLIST:
  828.             case EXACTION_DESTROYLOCAL:
  829.             case EXACTION_DESTROYLOCALCOND:
  830.             case EXACTION_DESTROYLOCALPOINTER:
  831.             case EXACTION_DESTROYLOCALARRAY:
  832.             case EXACTION_DESTROYBASE:
  833.             case EXACTION_DESTROYMEMBER:
  834.             case EXACTION_DESTROYMEMBERCOND:
  835.             case EXACTION_DESTROYMEMBERARRAY:
  836.             case EXACTION_DELETEPOINTER:
  837.             case EXACTION_DELETEPOINTERCOND:
  838.             case EXACTION_CATCHBLOCK:
  839.             case EXACTION_SPECIFICATION:
  840.                 continue;
  841.  
  842.             case EXACTION_TERMINATE:
  843.             default:
  844.                 terminate();            //    cannot find find most recent exception
  845.             }
  846.             break;
  847.         }
  848.         catchinfo=(CatchInfo *)(iter.current_FP+((ex_activecatchblock *)iter.info.action_pointer)->cinfo_ref);
  849.         context->throwtype    = (char *)catchinfo->typeinfo;
  850.         context->location    = catchinfo->location;
  851.         context->dtor        = catchinfo->dtor;
  852.         context->catchinfo    = catchinfo;
  853.     }
  854.     else context->catchinfo=0L;
  855.  
  856.     //    find matching exception handler
  857.  
  858.     iter.info        = info;
  859.     iter.current_SP    = context->SP;
  860.     iter.current_FP    = context->FP;
  861.     iter.current_R31 = context->GPR[31];
  862.     for(action=ExPPC_CurrentAction(&iter);; action=ExPPC_NextAction(&iter))
  863.     {
  864.         switch(action)
  865.         {
  866.         case EXACTION_CATCHBLOCK:
  867.             if(__throw_catch_compare(context->throwtype,((ex_catchblock *)iter.info.action_pointer)->catch_type,&offset))
  868.             {
  869.                 break;
  870.             }
  871.             continue;
  872.  
  873.         case EXACTION_SPECIFICATION:
  874.             if(!ExPPC_IsInSpecification(context->throwtype,(ex_specification *)iter.info.action_pointer))
  875.             {    //    unexpected specification
  876.                 ExPPC_HandleUnexpected(context,&info,(ex_specification *)iter.info.action_pointer);
  877.                 //    we will never return from this function call
  878.             }
  879.             continue;
  880.  
  881.         case EXACTION_ENDOFLIST:
  882.         case EXACTION_DESTROYLOCAL:
  883.         case EXACTION_DESTROYLOCALCOND:
  884.         case EXACTION_DESTROYLOCALPOINTER:
  885.         case EXACTION_DESTROYLOCALARRAY:
  886.         case EXACTION_DESTROYBASE:
  887.         case EXACTION_DESTROYMEMBER:
  888.         case EXACTION_DESTROYMEMBERCOND:
  889.         case EXACTION_DESTROYMEMBERARRAY:
  890.         case EXACTION_DELETEPOINTER:
  891.         case EXACTION_DELETEPOINTERCOND:
  892.         case EXACTION_ACTIVECATCHBLOCK:
  893.             continue;
  894.  
  895.         case EXACTION_TERMINATE:
  896.         default:
  897.             terminate();            //    cannot find matching catch block
  898.         }
  899.         break;
  900.     }
  901.  
  902.     //    we have found a matching catch block
  903.     catchblock=(ex_catchblock *)iter.info.action_pointer;
  904.     ExPPC_UnwindStack(context,&info,catchblock);
  905.  
  906.     //    initialize catch info struct
  907.     catchinfo=(CatchInfo *)(context->FP+catchblock->cinfo_ref);
  908.     catchinfo->location        = context->location;
  909.     catchinfo->typeinfo        = context->throwtype;
  910.     catchinfo->dtor            = context->dtor;
  911.     if(*context->throwtype=='*')
  912.     {    //    pointer match (create a pointer copy with adjusted offset)
  913.         catchinfo->sublocation    = &catchinfo->pointercopy;
  914.         catchinfo->pointercopy    = *(long *)context->location+offset;
  915.     }
  916.     else
  917.     {    //    traditional or class match (directly adjust offset)
  918.         catchinfo->sublocation    = (char *)context->location+offset;
  919.     }
  920.  
  921.     //    remember eventual stacktop (restored from catchinfo at end of catch block)
  922. //    catchinfo->stacktop = context->SP;    //    saved at try { ... } instead
  923.  
  924.     //    jump to exception handler
  925.     ExPPC_LongJump(context,info.TOC,info.current_function+catchblock->catch_pcoffset);
  926. }
  927.  
  928. /************************************************************************/
  929. /* Purpose..: Throw (rethrow) current exception                            */
  930. /* Input....: pointer to throw type (0L: rethrow)                        */
  931. /* Input....: pointer to complete throw object (0L: rethrow)            */
  932. /* Input....: pointer to throw object destructor (0L: no destructor        */
  933. /* Return...: ---                                                        */
  934. /************************************************************************/
  935. asm void __throw(char *throwtype, void *location, void *dtor)
  936. {
  937.         ThrowContext throwcontext;
  938.         
  939.         //    allocate a stack frame so we can use symbolic access to locals
  940.         fralloc
  941.         //    save GPRs so we can restore them during stack unwind
  942.         stmw    r13,throwcontext.GPR[13]
  943.         //    save FPRs so we can restore them during stack unwind
  944.         stfd    fp14,throwcontext.FPR[14]
  945.         stfd    fp15,throwcontext.FPR[15]
  946.         stfd    fp16,throwcontext.FPR[16]
  947.         stfd    fp17,throwcontext.FPR[17]
  948.         stfd    fp18,throwcontext.FPR[18]
  949.         stfd    fp19,throwcontext.FPR[19]
  950.         stfd    fp20,throwcontext.FPR[20]
  951.         stfd    fp21,throwcontext.FPR[21]
  952.         stfd    fp22,throwcontext.FPR[22]
  953.         stfd    fp23,throwcontext.FPR[23]
  954.         stfd    fp24,throwcontext.FPR[24]
  955.         stfd    fp25,throwcontext.FPR[25]
  956.         stfd    fp26,throwcontext.FPR[26]
  957.         stfd    fp27,throwcontext.FPR[27]
  958.         stfd    fp28,throwcontext.FPR[28]
  959.         stfd    fp29,throwcontext.FPR[29]
  960.         stfd    fp30,throwcontext.FPR[30]
  961.         stfd    fp31,throwcontext.FPR[31]
  962.         //    save CR so we can restore it during stack unwind
  963.         mfcr    r3
  964.         stw        r3,throwcontext.CR;
  965.         //    throwcontext.SP = throwcontext.throwSP = <stack pointer of caller>;
  966.         //    throwcontext.returnaddr = <return address into caller>;
  967.         lwz        r3,0(sp)
  968.         lwz        r4,8(r3)
  969.         stw        r3,throwcontext.SP;
  970.         stw        r3,throwcontext.throwSP;
  971.         stw        r4,throwcontext.returnaddr;
  972.         //    throwcontext.throwtype = throwtype;
  973.         lwz        r3,throwtype
  974.         stw        r3,throwcontext.throwtype
  975.         //    throwcontext.location = location;
  976.         lwz        r3,location
  977.         stw        r3,throwcontext.location
  978.         //    throwcontext.dtor = dtor;
  979.         lwz        r3,dtor
  980.         stw        r3,throwcontext.dtor
  981.         //    call __ex_throwhandler(&throwcontext);
  982.         la        r3,throwcontext
  983.         bl        ExPPC_ThrowHandler
  984.         nop
  985.         //    (will never get here)
  986.         frfree
  987.         blr
  988. }
  989.  
  990. /************************************************************************/
  991. /* Purpose..: Deinitialize CatchInfo struct                                */
  992. /* Input....: pointer to catchinfo struct                                */
  993. /* Return...: ---                                                        */
  994. /************************************************************************/
  995. void __end__catch(CatchInfo *catchinfo)
  996. {
  997.     if (catchinfo->location && catchinfo->dtor)
  998.         DTORCALL_COMPLETE(catchinfo->dtor,catchinfo->location);
  999. }
  1000.